#include <iostream>
#include <string.h>
#include "server.h"

// Default constructor uses default port
//
Server::Server() :
    m_fd(0), 
    m_port(kDefaultPort)
{
}

// Constructor takes port as parameter
//
Server::Server(short port) :
    m_fd(0),
    m_port(port)
{
}

// Destructor closes the socket
//
Server::~Server()
{
    close();
}

// Prepare server for incoming client connections
//
bool Server::open()
{
    struct sockaddr_in addr;                    // server address
    memset(&addr, 0, sizeof(addr));
    
    addr.sin_family = AF_INET;
    addr.sin_port = htons(m_port);              // host to network (big endian)
    addr.sin_addr.s_addr = INADDR_ANY;
    
    m_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (m_fd != -1)
    {
        
        int err = bind(m_fd, (sockaddr*) &addr, sizeof(addr));
        if (err == 0)
        {
            if (listen(m_fd, kMaxListen) == 0)
            {
                return true;
            }
        }
    }
    return false;
}

// Close socket; shuts down server
//
bool Server::close()
{
    if (m_fd != 0)
    {
        ::close(m_fd);
        m_fd = 0;
    }
    return true;
}

// Waits for a client connection; once established it forks another process
// to service the client.
//
bool Server::wait()
{
    bool endWaiting = true;
    
    struct sockaddr_in addr;                    // client address
    memset(&addr, 0, sizeof(addr));
    
    socklen_t addr_len = sizeof(addr);
  
    std::cout << "Waiting for a client.\n";

    // Block here until a client connection is made
    //
    int fd = accept(m_fd, (sockaddr*) &addr, &addr_len);
        
    std::cout << "Accepted client, forking handler.\n";

    // fork() creates a copy of the process and continues to
    // run from the same location in each process.
    //
    // The parent process gets the child process id or -1 if error.
    // The child process gets 0 for the process id.
    //
    pid_t pid = fork();
    
    // pid == 0, means child process is running
    //
    if (pid == 0)
    {
        close();
        clientHandler(fd, &addr);
     }
    // pid > 0, means parent process is running
    //
    else if (pid > 0)
    {
        ::close(fd);
        endWaiting = false;                     // go back to waiting for another client
    }
    // pid == -1, means error forking process
    //
    else 
    {
        std::cout << "Error encountered while creating a fork.\n";
    }
    
    return endWaiting;
}

// Client handler reads a command name to execute and sends all output
// back to the client. The connection is closed so only one command
//
void Server::clientHandler(int fd, sockaddr_in* addr)
{
    char buffer[256];
    int  len = sizeof(buffer);
    memset(buffer, '\0', len);
    
    int n = read(fd, buffer, len - 1);
    if (n > 0)
    {
        std::cout << "Executing " << buffer << ".\n";
        
        // Launch the process and read the pipe so it can be sent to the socket
        //
        FILE* fp = popen(buffer, "r");
        if (fp != NULL)
        {
            memset (buffer, '\0', len);
            while (fgets(buffer, len - 1, fp))
            {
                // Write out through the socket
                //
                n = write(fd, buffer, strlen(buffer));
                if (n != strlen(buffer))
                {
                    std::cout << "Error: Not all characters written to socket.\n";
                }
                memset (buffer, '\0', len);
            }
            fclose(fp);
        }
        
        std::cout << "Execution complete.\n";
    }
         
    ::close(fd);
}
